package com.tool.cn.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.CRC32;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 读写文件
 * 
 * @author wangzh
 * 2016年9月19日 上午11:46:20
 */
public final class FileUtil {
	
	private static final Log log = LogFactory.getLog(FileUtil.class);
	
	/**
	 * 读取字节文件
	 */
	public static  byte[]  readFile(String fileUrl){
		try {
			@SuppressWarnings("resource")
			FileInputStream input=new FileInputStream(new File(fileUrl));
			
			byte[] result=new byte[input.available()];
			 //可能溢出,简单起见就不考虑太多,如果太大就要另外想办法，比如一次传入固定长度byte[]  
			int size=2048;
			byte[] bytes  = new byte[size];
			int num=0;
			while(input.read(bytes)!=-1){
				if(result.length-size>num*size){
					//第一个是要复制的数组，第二个是从要复制的数组的第几个开始，第三个是复制到那，四个是复制到的数组第几个开始，最后一个是复制长度
					System.arraycopy(bytes, 0, result, num*size, size);   
				}else{
					System.arraycopy(bytes, 0, result, num*size, result.length-(num*size)); 
				}
				
				num++;
			}
			  
			return result;
		} catch (FileNotFoundException e) {
			log.error("未发现文件"+e);
		} catch (IOException e) {
			log.error("IO流读写异常"+e);
		}
		return null;
	}
	
	
	/**
	 * 写入 字节文件
	 * state 是否追加  true追加  false 覆盖
	 */
	public static boolean writeFile(byte[] result,String fileUrl,boolean state){
		 try {
			FileOutputStream output=new FileOutputStream(fileUrl,state);
			 output.write(result);
			 output.flush();
			 output.close();
			 return true;
		} catch (FileNotFoundException e) {
			log.error("未发现文件"+e);
		} catch (IOException e) {
			log.error("IO流读写异常"+e);
		}
		 return false;
	}
	
	/**
	 * 清空文件
	 */
	public static boolean cleanFile(String fileUrl){
		return writeFile("".getBytes(), fileUrl, false);
	}
	
	/**
     * 删除空目录
     * @param dir 将要删除的目录路径
     */
    public static void doDeleteEmptyDir(String dir) {
        boolean success = (new File(dir)).delete();
        if (success) {
            log.info("Successfully deleted empty directory: " + dir);
        } else {
        	log.info("Failed to delete empty directory: " + dir);
        }
    }

    /**
     * 递归删除目录下的所有文件及子目录下所有文件
     * @param dir 将要删除的文件目录
     */
    public static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            //递归删除目录中的子目录下
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }
    
    /**
     * 获取路径下文件，过滤.和~开头，tmp结尾文件
     * @param url
     * @param param
     * @return
     */
    public static String[] getFile(String url){
    	File input=new File(url);
		String[] fileName=input.list(new FilenameFilter() {
			@Override
			public boolean accept(File paramFile, String paramString) {
				System.out.println(paramString);
				
				if(paramString.startsWith(".")||paramString.endsWith("~")||paramString.endsWith("tmp")){
					return false;
				}
				return true;
			}
		});
		
		return fileName;
    }
    
    /**
     * 获取文件名，不包含后缀
     * @param file
     * @return
     */
	public static String getName(File file) {
		String name=file.getName();
		int num=name.indexOf(".");
		name=name.substring(0,num);
		return name;
	}
	
	/**
	 * 获取文件后缀，包含点
	 * @param file
	 * @return
	 */
	public static String getFileType(File file){
		String name=file.getName();
		int num=name.indexOf(".");
		String fileType=name.substring(num);
		return fileType;
	}
	
	/**
	 * 对一个文件获取md5值
	 */
	public static String getMD5(File file) throws IOException,NoSuchAlgorithmException {
 
		MessageDigest messagedigest = MessageDigest.getInstance("MD5");
		FileInputStream in = new FileInputStream(file);
		FileChannel ch = in.getChannel();
		MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,
				file.length());
		messagedigest.update(byteBuffer);
		in.close();
		return bufferToHex(messagedigest.digest());
	}
	
	/***
	 * 计算SHA1码
	 * 
	 * @return String 适用于上G大的文件
	 * @throws NoSuchAlgorithmException
	 * */
	public static String getSha1(File file) throws OutOfMemoryError,IOException, NoSuchAlgorithmException {
		MessageDigest messagedigest = MessageDigest.getInstance("SHA-1");
		FileInputStream in = new FileInputStream(file);
		FileChannel ch = in.getChannel();
		MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0,file.length());
		messagedigest.update(byteBuffer);
		in.close();
		return bufferToHex(messagedigest.digest());
	}
	
	/**
	 * 获取文件CRC32码
	 * 
	 * @return String
	 * */
	public static String getCRC32(File file) {
		CRC32 crc32 = new CRC32();
		FileInputStream fileInputStream = null;
		try {
			fileInputStream = new FileInputStream(file);
			byte[] buffer = new byte[8192];
			int length;
			while ((length = fileInputStream.read(buffer)) != -1) {
				crc32.update(buffer, 0, length);
			}
			return crc32.getValue() + "";
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				if (fileInputStream != null)
					fileInputStream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * @Description 计算二进制数据
	 * */
	private static String bufferToHex(byte bytes[]) {
		int m=0, n=bytes.length;
		StringBuffer stringbuffer = new StringBuffer(2 * n);
		int k = m + n;
		for (int l = m; l < k; l++) {
			appendHexPair(bytes[l], stringbuffer);
		}
		return stringbuffer.toString();
	}
	
	private static void appendHexPair(byte bt, StringBuffer stringbuffer) {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6','7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
		char c0 = hexDigits[(bt & 0xf0) >> 4];
		char c1 = hexDigits[bt & 0xf];
		stringbuffer.append(c0);
		stringbuffer.append(c1);
	}
	
    /**
     * 下载文件
     * 
     * 使用方法 js调用传参：
     * window.location.href=请求路径?url=参数
     */
    public static boolean downLoadFile(String url,HttpServletResponse response){
    	log.info(url);
           
    	try {
			File file = new File(url);  //根据文件路径获得File文件
			//设置文件类型(这样设置就不止是下Excel文件了，一举多得)
			if(url.endsWith("pdf")){
			   response.setContentType("application/pdf;charset=UTF-8");
			}else if(url.endsWith("csv")){
			   response.setContentType("application/msexcel;charset=UTF-8");
			}else if(url.endsWith("doc")){
			   response.setContentType("application/msword;charset=UTF-8");
			}else if(url.endsWith("xls")){
			    response.setContentType("application/msexcel;charset=UTF-8");
			}else if(url.endsWith("zip")){
				response.setContentType("application/zip;charset=UTF-8");
			}else if(url.endsWith("cap")||url.endsWith("pcap")){
				response.setContentType("application/vnd.tcpdump.pcap;charset=UTF-8");
			}
			//mine http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types
			
			//文件名
			response.setHeader("Content-Disposition", "attachment;filename=" +file.getName());
			response.setContentLength((int) file.length());
			byte[] buffer = new byte[4096];// 缓冲区
			BufferedOutputStream output = null;
			BufferedInputStream input = null;
			try {
			  output = new BufferedOutputStream(response.getOutputStream());
			  input = new BufferedInputStream(new FileInputStream(file));
			  int n = -1;
			  //遍历，开始下载
			  while ((n = input.read(buffer, 0, 4096)) > -1) {
			     output.write(buffer, 0, n);
			  }
			  output.flush();   //不可少
			  response.flushBuffer();//不可少
			} catch (Exception e) {
			  //异常自己捕捉       
			} finally {
			   //关闭流，不可少
			   if (input != null)
			        input.close();
			   if (output != null)
			        output.close();
			}
			return true;
		} catch (UnsupportedEncodingException e) {
			log.error(e,e);
		} catch (IOException e) {
			log.error(e,e);
		}
    	return false;
    }
	
}
